package com.ncmmall.mall.controller.business.order;

import com.ncmmall.application.business.order.OrderApplication;
import com.ncmmall.application.securitys.logs.OperationLogApplication;
import com.ncmmall.application.util.WechatMessageUtils;
import com.feijin.commons.excel.ExcelExports;
import com.feijin.commons.exceptions.IllegalRequestException;
import com.feijin.commons.lang.ArithUtils;
import com.feijin.commons.lang.Dates;
import com.feijin.commons.webs.Webs;
import com.ncmmall.domain.business.cloudstore.CloudStoreGoods;
import com.ncmmall.domain.business.cloudstore.CloudStoreGoodsRelevance;
import com.ncmmall.domain.business.cloudstore.QCloudStoreGoods;
import com.ncmmall.domain.business.express.Express;
import com.ncmmall.domain.business.express.QExpress;
import com.ncmmall.domain.business.goods.Goods;
import com.ncmmall.domain.business.merchant.freight.MerchantFreight;
import com.ncmmall.domain.business.merchant.freight.MerchantFreightTemplate;
import com.ncmmall.domain.business.merchant.freight.QMerchantFreight;
import com.ncmmall.domain.business.merchant.freight.QMerchantFreightTemplate;
import com.ncmmall.domain.business.order.Order;
import com.ncmmall.domain.business.order.OrderDetail;
import com.ncmmall.domain.business.order.QOrder;
import com.ncmmall.domain.security.user.WebUser;
import com.ncmmall.mall.controller.securitys.shiro.Securitys;
import com.ncmmall.mall.params.PageParams;
import com.ncmmall.querychannel.QueryPage;
import com.ncmmall.querychannel.QueryPageRequest;
import com.ncmmall.querychannel.service.QueryChannelService;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 订单管理
 *
 * @author linxs
 * @date 2019-07-10 17:44
 */
@Controller
@RequestMapping(value = "/merchant/order")
@Slf4j
public class MerchantOrderController {

    @Autowired
    private QueryChannelService queryChannelService;

    @Autowired
    private OrderApplication orderApplication;

    @Autowired
    private OperationLogApplication logApplication;

    /**
     * 订单列表
     */
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public String list(Model model, PageParams pageParams, Order order) throws ParseException {
        QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageParams.getPageNo());
        Map<String, Object> params = Maps.newHashMap();
        params.put("id", Securitys.currentUser().getId());
        String hql = builderSQL("select u from Order u where u.merchant.id = :id and u.isIssuingType = 0 ", params, order);
        QueryPage<Order> page = queryChannelService.findPage(hql, pageRequest.setParams(params), Order.class);
        model.addAttribute("page", page).addAttribute("params", order);

        return "merchant/order/list";
    }


    /**
     * 导出Excel
     */
    @RequestMapping(value = "/exports", method = RequestMethod.GET)
    private void exports(HttpServletRequest request, HttpServletResponse response, Order order) throws ParseException {
        Map<String, Object> params = new HashMap<>();
        params.put("id", Securitys.currentUser().getId());

        String sql = "select u from Order u where u.merchant.id = :id and u.isIssuingType = 0 ";
        String hql = builderSQL(sql, params, order);

        List<Order> result = queryChannelService.findAll(hql, params, Order.class);
        for (Order item : result) {

            List<String> names = Lists.newArrayList();
            for (OrderDetail detail : item.getDetails()) {
                names.add(detail.getGoodsName());
            }
            item.setExpressCompany(Joiner.on("、").join(names));
        }

        Map<String, Object> data = ImmutableMap.of("result", result);
        ExcelExports document = new ExcelExports.Templates().formTemplate("merchantOrders.ftl").bind(data).store("merchantOrders.xls").build();

        try {
            document.generate();
            Webs.download(request, response, document.getFile(), "订单" + Dates.transDateToStr(new Date()) + ".xls");
        } catch (Exception e) {
            log.error("[导出异常]", e);
        }
    }

    /**
     * 去发货
     */
    @RequestMapping(value = "/{id}/delivery", method = RequestMethod.GET)
    private String delivery(Model model, @PathVariable("id") long id) {

        Order order = queryChannelService.findOne(QOrder.order.id.eq(id), Order.class);
        List<Express> expresses = queryChannelService.findAll(QExpress.express.status.eq(2), Express.class);
        List<CloudStoreGoodsRelevance> relevancesList = Lists.newArrayList();


        for (OrderDetail detail : order.getDetails()) {
            Goods goods = detail.getSku().getGoods();
            List<CloudStoreGoodsRelevance> relevances = queryChannelService.findAll("select c from CloudStoreGoodsRelevance c where c.goods.id = :id and c.cloudStoreGoods.status = 1 ", ImmutableMap.of("id", goods.getId()), CloudStoreGoodsRelevance.class);
            relevancesList.addAll(relevances);
        }

        model.addAttribute("order", order).addAttribute("expresses", expresses).addAttribute("_method", "PUT").addAttribute("relevancesList", relevancesList);
        return "merchant/order/delivery";
    }


    /**
     * 发货
     */
    @RequestMapping(value = "/{id}/delivery", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> delivery(HttpServletRequest request, @RequestHeader("X-Requested-With") String requestWith, Order params) {
        try {
            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }

            Order order = queryChannelService.findOne(QOrder.order.id.eq(params.getId()), Order.class);

            long id = orderApplication.delivery(params);
            logApplication.eventOfMerchant(Securitys.currentUser(), "订单发货", Securitys.getIp(request));

            Express express = queryChannelService.findOne(QExpress.express.expressCompanyCode.eq(params.getExpressCode()), Express.class);

            JSONObject item = new JSONObject();
            item.put("number2", JSONObject.fromObject(ImmutableMap.of("value", order.getOrderNo())));
            item.put("date5", JSONObject.fromObject(ImmutableMap.of("value", new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date()))));
            item.put("thing1", JSONObject.fromObject(ImmutableMap.of("value", order.getDetails().get(0).getSku().getGoods().getName())));
            item.put("phrase3", JSONObject.fromObject(ImmutableMap.of("value", express.getName())));
            item.put("character_string4", JSONObject.fromObject(ImmutableMap.of("value", params.getExpressesNo())));

            WechatMessageUtils.send(order.getMember().getOpenId(), "0CIwJhN8oBSl-zGgT7IRL-k0HfkWt-0duPrGcFayfBo", item.toString());

            return ImmutableMap.of("status", true, "id", id);

        } catch (Exception e) {
            log.error("[发货异常]", e);
            return ImmutableMap.of("status", false, "message", "发货失败");
        }
    }

    /**
     * 计算提货单运费
     */
    @RequestMapping(value = "/queryFreightPrice", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> queryFreightPrice(@RequestParam("id") long id, @RequestParam("cloudStoreId") long cloudStoreId, @RequestParam("count") int quantity) {
        try {

            Order order = queryChannelService.findOne(QOrder.order.id.eq(id), Order.class);
            CloudStoreGoods cloudStoreGoods = queryChannelService.findOne(QCloudStoreGoods.cloudStoreGoods.id.eq(cloudStoreId), CloudStoreGoods.class);

            double price = totalFreightPrice(order.getDeliveryCity(), cloudStoreGoods.getGoods(), quantity);

            return ImmutableMap.of("status", true, "price", price);

        } catch (Exception e) {
            return ImmutableMap.of("status", false);
        }
    }


    private double totalFreightPrice(String city, Goods goods, int quantity) {


        WebUser merchant = goods.getMerchant();
        double freightPrice = 0;

        //运费模板
        if (goods.getSupplierPostageType() == 1) {

            MerchantFreight freight = queryChannelService.findOne(QMerchantFreight.merchantFreight.city.eq(city).and(QMerchantFreight.merchantFreight.merchant.eq(merchant).and(QMerchantFreight.merchantFreight.template.id.eq(goods.getSupplierFreightTemplate().getId()))), MerchantFreight.class);

            MerchantFreightTemplate template = queryChannelService.findOne(QMerchantFreightTemplate.merchantFreightTemplate.id.eq(goods.getSupplierFreightTemplate().getId()), MerchantFreightTemplate.class);

            //按重量
            if (template.getType() == 1) {

                if (null != freight) {   //拿到了模板内设置的区域运费

                    double gram = ArithUtils.mul(goods.getGram(), quantity);//总重量

                    if (gram <= freight.getFirstWeight()) {
                        freightPrice += freight.getFirstWeightAmount();
                    } else {
                        double fistWeightAmount = freight.getFirstWeightAmount();
                        double weight = ArithUtils.sub(gram, freight.getFirstWeight());

                        if (weight < freight.getOtherWeight()) {
                            freightPrice += ArithUtils.add(fistWeightAmount, freight.getOtherWeightAmount());
                        } else {
                            freightPrice += ArithUtils.add(fistWeightAmount, ArithUtils.mul(Math.ceil(ArithUtils.div(weight, freight.getOtherWeight(), 2)), freight.getOtherWeightAmount()));
                        }
                    }

                } else {

                    double gram = ArithUtils.mul(goods.getGram(), quantity);//总重量

                    if (gram <= template.getDefaultWeight()) {
                        freightPrice += template.getDefaultWeightAmount();
                    } else {

                        double fistWeightAmount = template.getDefaultWeightAmount();
                        double weight = ArithUtils.sub(gram, template.getDefaultWeight());

                        if (weight < template.getDefaultAddWeight()) {
                            freightPrice += ArithUtils.add(fistWeightAmount, template.getDefaultAddWeightAmount());
                        } else {
                            freightPrice += ArithUtils.mul(Math.ceil(ArithUtils.div(weight, template.getDefaultAddWeight(), 2)), template.getDefaultAddWeightAmount());
                        }
                    }

                }

            }

            //按件
            if (template.getType() == 2) {

                if (null != freight) {

                    if (quantity <= freight.getFirstPiece()) {
                        freightPrice += freight.getFirstPieceAmount();
                    } else {
                        freightPrice += ArithUtils.add(freight.getFirstPieceAmount(), ArithUtils.mul(ArithUtils.sub(quantity, freight.getFirstPiece()), freight.getOtherPieceAmount()));
                    }

                } else {

                    if (quantity <= template.getDefaultPiece()) {
                        freightPrice += template.getDefaultPieceAmount();
                    } else {
                        freightPrice += ArithUtils.add(template.getDefaultPieceAmount(), ArithUtils.mul(ArithUtils.sub(quantity, template.getDefaultPiece()), template.getDefaultAddPieceAmount()));
                    }

                }

            }

        } else if (goods.getSupplierPostageType() == 2) {      //包邮

            freightPrice += ArithUtils.add(freightPrice, 0);

        } else if (goods.getSupplierPostageType() == 3) {        //指定运费

            freightPrice += ArithUtils.add(freightPrice, ArithUtils.mul(goods.getSupplierPostage(), quantity));

        }

        return freightPrice;


    }

    /**
     * 已提货
     */
    @RequestMapping(value = "/{id}/shipping", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> shipping(HttpServletRequest request, @RequestHeader("X-Requested-With") String requestWith, @PathVariable("id") long id) {
        try {
            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }

            orderApplication.shipping(queryChannelService.findOne(QOrder.order.id.eq(id), Order.class));
            logApplication.eventOfMerchant(Securitys.currentUser(), "订单自提", Securitys.getIp(request));

            return ImmutableMap.of("status", true);

        } catch (Exception e) {
            log.error("[提货异常]", e);
            return ImmutableMap.of("status", false, "message", "提货失败");
        }
    }

    /**
     * 去修改订单价格
     */
    @RequestMapping(value = "/{id}/modifyAmount", method = RequestMethod.GET)
    private String modifyAmount(Model model, @PathVariable("id") long id) {

        Order order = queryChannelService.findOne(QOrder.order.id.eq(id), Order.class);

        model.addAttribute("order", order).addAttribute("_method", "PUT");

        return "merchant/order/modifyAmount";
    }

    @RequestMapping(value = "/{id}/modifyAmount", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> modifyAmount(HttpServletRequest request, @RequestHeader("X-Requested-With") String requestWith, Order params) {
        try {
            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }

            orderApplication.modifyAmount(params);

            logApplication.eventOfMerchant(Securitys.currentUser(), "修改订单价格", Securitys.getIp(request));

            return ImmutableMap.of("status", true);

        } catch (Exception e) {
            log.error("[发货异常]", e);
            return ImmutableMap.of("status", false, "message", "发货失败");
        }
    }


    /**
     * 查看详情
     */
    @RequestMapping(value = "/{id}/detail", method = RequestMethod.GET)
    public String detail(Model model, @PathVariable("id") long id) {

        Order order = queryChannelService.findOne(QOrder.order.id.eq(id), Order.class);
        List<Goods> giftGoodses = new ArrayList<>();

        //赠品活动订单
        if (order.getMarketingType() == 1) {
            giftGoodses = queryChannelService.findAll("select g.goods from GiftGoods g where g.gift.id = :id ", ImmutableMap.of("id", order.getGiftActivity().getId()), Goods.class);
        }

        double detailPrice = 0;
        for (OrderDetail detail : order.getDetails()) {
            detail.setPrice(ArithUtils.mul(detail.getQuantity(), detail.getSku().getPrice()));
            detailPrice = ArithUtils.add(detail.getPrice(), detailPrice);
        }

        order.setGoodsSubtotalPrice(detailPrice);

        model.addAttribute("order", order);
        model.addAttribute("giftgoodses", giftGoodses);

        return "merchant/order/detail";
    }

    /**
     * 查看详情
     */
    @RequestMapping(value = "/{orderNo}/orderDetail", method = RequestMethod.GET)
    private String detail(Model model, @PathVariable("orderNo") String orderNo) {

        Order order = queryChannelService.findOne(QOrder.order.orderNo.eq(orderNo), Order.class);


        List<Goods> giftGoodses = Lists.newArrayList();

        //赠品活动订单
        if (order.getMarketingType() == 1) {
            giftGoodses = queryChannelService.findAll("select g.goods from GiftGoods g where g.gift.id = :id ", ImmutableMap.of("id", order.getGiftActivity().getId()), Goods.class);
        }

        model.addAttribute("order", order);
        model.addAttribute("giftgoodses", giftGoodses);

        return "merchant/order/detail";
    }


    /**
     * 条件筛选
     */
    private String builderSQL(String sql, Map<String, Object> params, Order order) throws ParseException {

        if (order.getStatus() > 0) {
            sql += " and u.status = :status ";
            params.put("status", order.getStatus());
        }

        if (null != order.getMerchant() && order.getMerchant().getId() != 0) {
            sql += " and u.merchant.id = :mid ";
            params.put("mid", order.getMerchant().getId());
        }

        if (!Strings.isNullOrEmpty(order.getOrderNo())) {
            sql += " and u.orderNo like :orderno ";
            params.put("orderno", "%" + order.getOrderNo() + "%");
        }

        if (!Strings.isNullOrEmpty(order.getDeliveryMobile())) {
            sql += " and u.deliveryMobile like :deliverymobile ";
            params.put("deliverymobile", "%" + order.getDeliveryMobile() + "%");
        }

        if (!Strings.isNullOrEmpty(order.getDeliveryName())) {
            sql += " and u.deliveryName like :deliveryname ";
            params.put("deliveryname", "%" + order.getDeliveryName() + "%");
        }

        if (!Strings.isNullOrEmpty(order.getBeginTime())) {
            sql += " and u.createTime >= :btime ";
            params.put("btime", new Date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(order.getBeginTime() + " 00:00:00").getTime()));
        }

        if (!Strings.isNullOrEmpty(order.getEndTime())) {
            sql += " and u.createTime <= :etime ";
            params.put("etime", new Date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(order.getEndTime() + " 23:59:59").getTime()));
        }

        if (!Strings.isNullOrEmpty(order.getOrderByCreateTime())) {
            sql += " order by u.createTime " + order.getOrderByCreateTime();
        }

        if (!Strings.isNullOrEmpty(order.getOrderByPrice())) {
            sql += " order by u.price " + order.getOrderByPrice();
        }

        if (!sql.contains("order by")) {
            sql += " order by u.createTime desc ";
        }

        return sql;
    }

}
